package org.news.web.utils;

import cn.hutool.core.date.DateUtil;
import cn.hutool.core.util.ObjUtil;
import com.alibaba.fastjson.JSONObject;
import com.aliyuncs.exceptions.ClientException;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.core.toolkit.ObjectUtils;
import com.vladsch.flexmark.html2md.converter.FlexmarkHtmlConverter;
import lombok.NoArgsConstructor;
import lombok.RequiredArgsConstructor;
import org.apache.tomcat.util.http.fileupload.disk.DiskFileItem;
import org.apache.tomcat.util.http.fileupload.disk.DiskFileItemFactory;
import org.dromara.common.core.utils.MapstructUtils;
import org.dromara.common.core.utils.StringUtils;
import org.dromara.common.redis.utils.RedisUtils;
import org.dromara.system.domain.vo.SysOssVo;
import org.dromara.system.service.impl.SysOssServiceImpl;
import org.news.web.constant.NewsConstant;
import org.news.web.domain.News;
import org.news.web.domain.bo.NewsBo;
import org.news.web.domain.bo.PythonNewsBo;
import org.news.web.domain.vo.NewsVo;
import org.news.web.mapper.NewsMapper;
import org.news.web.redis.RedisConstant;
import org.news.web.service.INewsService;
import org.redisson.api.RBucket;
import org.redisson.api.RedissonClient;
import org.springframework.http.MediaType;
import org.springframework.scheduling.annotation.Scheduled;
import org.springframework.stereotype.Service;
import org.springframework.web.multipart.MultipartFile;

import java.io.*;
import java.net.HttpURLConnection;
import java.net.URL;
import java.nio.ByteBuffer;
import java.nio.channels.Channels;
import java.nio.channels.ReadableByteChannel;
import java.nio.channels.WritableByteChannel;
import java.util.ArrayList;
import java.util.Date;
import java.util.List;
import java.util.Set;
import java.util.stream.Collectors;

@Service
@RequiredArgsConstructor
public class HotRankUtils {
    private final static int VIEW_WEIGHT = 1;
    private final static int LIKE_WEIGHT = 5;
    private final static int FAVORITE_WEIGHT = 10;

    private final NewsMapper newsMapper;

    private final INewsService iNewsService;

    private final SysOssServiceImpl ossService;



    // 更新项目评分
    public void updateScore(long newId, long views, long likes, long favorites) {
        // 计算综合评分
        double score = views * VIEW_WEIGHT + likes * LIKE_WEIGHT + favorites * FAVORITE_WEIGHT;
        System.out.println("newId=>>>score:"+score);
        // 更新有序集合中的评分
        RedisUtils.setCacheZSet(RedisConstant.HOT_BANG, score, newId);
    }

    // 获取热门排行榜
    public static List<Integer> getHotRanking() {
        // 按照评分从高到低获取排行榜
        return RedisUtils.getRankZset(RedisConstant.HOT_BANG, 0, 49);
    }

    // 定时任务：每隔一段时间更新排行榜
    @Scheduled(fixedRate = 120000) // 每隔120秒执行一次
    public void updateHotRanking() {
//        获取所有已经发布的新闻
        List<NewsVo> newsVos = newsMapper.selectVoList(new LambdaQueryWrapper<News>().eq(News::getApplyStatus, NewsConstant.FaBu));

//        更新排行榜
        newsVos.forEach( news ->{
            updateScore(news.getNewsId(),news.getViews(),news.getLikes(),news.getFavorites());
        });
    }



    @Scheduled(fixedRate = 6000*5) // 每隔5分钟执行一次 更新新闻当中的点赞数量和收藏数量
    public void updateNewsLikeOrFavo() {
//        获取所有已经发布的新闻
        List<News> newsVos = newsMapper.selectList(new LambdaQueryWrapper<News>().eq(News::getApplyStatus, NewsConstant.FaBu));
        newsVos.forEach(item ->{
//            批量更新所有新闻的点赞和收藏数据
            Long likeCount = iNewsService.getLikeCount(item.getNewsId());
            Long favoCount = iNewsService.getFavoCount(item.getNewsId());
            item.setLikes(likeCount);
            item.setFavorites(favoCount);
        });
//        批量更新所有
        newsMapper.updateBatchById(newsVos);
    }

    @Scheduled(fixedRate = 6000*2)// 每隔2分钟执行一次 更新新闻当中的审核通过并更新成为发布
    public void updateNewsStatus(){
        //        获取所有已经审核通过的新闻
        List<News> newsVos = newsMapper.selectList(new LambdaQueryWrapper<News>().eq(News::getApplyStatus, NewsConstant.shenHeTong));

        List<News> news = new ArrayList<>();
        for (News item : newsVos) {
            if(item.getPublishTime() == null || new Date().getTime() >= item.getPublishTime().getTime()){
                //            更新状态为发布
                item.setApplyStatus(NewsConstant.FaBu);
                news.add(item);
            }
        }
        if(news.size() >0){
            //        批量更新
            newsMapper.updateBatchById(news);
        }
    }





//    更新所有爬取到的新闻信息
//    每天12点进行更新
    @Scheduled(cron = "0 0 12 * * ?")
    public void UpdateNewsInfo() throws UnsupportedEncodingException, ClientException {
//        获取记录爬虫的keys
        List<String> keys = RedisConstant.PythonKeys;

        RedissonClient client = RedisUtils.getClient();
        for (String key : keys) {
//            获取redis中爬取到的jsonString数据
            System.out.println("key ================= :::"+key);

            RBucket<String> bucket = client.getBucket(key, null);
            String strJsonInfo =  bucket.get();
//            判断里面是否有相关数据
            if(strJsonInfo == null || strJsonInfo.equals("")){
                continue;
            }
//           进行数据格式处理和转换对象
//            转换为爬虫数据对象
            List<PythonNewsBo> pythonNewsBos = JSONObject.parseArray(bucket.get(), PythonNewsBo.class);
//            把html转为md
            for (PythonNewsBo pythonNewsBo : pythonNewsBos) {
                pythonNewsBo.setContent(htmlToMd(pythonNewsBo.getContent()));
            }


            System.out.println("size:::"+pythonNewsBos.size());
            //            通过该方法转换为NewsBo对象 并且把爬取图片url信息转化为图片信息并上传到oss中
            List<NewsBo> news = PythonDateToNews(pythonNewsBos,key);
            if(news == null || news.size() == 0){
                continue;
            }
//            进行批量插入
//      把数据写入到数据库中
            for (NewsBo news1 : news) {
                System.out.println("插入新闻信息 标题：title:"+news1.getTitle()+"====>>>"+iNewsService.insertByBo(news1));
            }
        }
    }


//    每天11点30调用python脚本 进行资源的获取
    @Scheduled(cron = "0 30 11 * * ?")
    public static void pythonRun(){
        String pythonSP = "C:\\Users\\Admin\\Desktop\\news-recommen-master\\爬虫\\1.py";
        String[] command = {"python",pythonSP};



        try {
            System.out.println("脚本开始执行 ！！！！！！！！！！！！！");
            ProcessBuilder pb = new ProcessBuilder(command);
            Process process = pb.start();
            InputStream inputStream = process.getErrorStream();
            InputStreamReader inputStreamReader = new InputStreamReader(inputStream);
            BufferedReader bufferedReader = new BufferedReader(inputStreamReader);

            String OutLine = "";

            while((OutLine = bufferedReader.readLine()) != null){
                System.out.println(OutLine);
            }


            System.out.println("脚本执行结束！！！！！！！！！！！！！");

        } catch (IOException e) {
            System.out.println("python脚本执行异常!");
            throw new RuntimeException(e);
        }

    }


    public static String htmlToMd(String html){
        String markdown = null;
        if(html != null && StringUtils.isNotBlank(html)){
            markdown = FlexmarkHtmlConverter.builder().build().convert(html);
        }
//        去除掉无效内容
//        {#.*?}
        markdown = markdown.replaceAll("\\{#.*?\\}","");
        return markdown;
    }

    private List<NewsBo> PythonDateToNews(List<PythonNewsBo> pythonNewsBos,String key) {


        List<NewsBo> news = new ArrayList<>();

        for (PythonNewsBo pythonNewsBo : pythonNewsBos) {
            NewsBo newsEn = new NewsBo();
            // 格式转换日期 //        05/08/2024 08:02:05
            Date date = DateUtil.parse(pythonNewsBos.get(0).getTime(), "MM/dd/yyyy HH:mm:ss");
//            设置发布时间
            newsEn.setPublishTime(date);
//            设置内容
            newsEn.setContent(pythonNewsBo.getContent());
//            设置标题
            newsEn.setTitle(pythonNewsBo.getTitle());

            // 把封面url上传到本项目的存储中 返回ossid
            MultipartFile multipartFile = FileUtils.UrlToMultpartFile(pythonNewsBo.getCoverUrl());
            if(multipartFile == null){
                newsEn.setCover(NewsConstant.DF_cover);
            }else{
                SysOssVo upload = ossService.upload(multipartFile);
                if (upload==null){
//                  默认图片
                    newsEn.setCover(NewsConstant.DF_cover);
                }else{
                    newsEn.setCover(String.valueOf(upload.getOssId()));
                }
            }

//


            // 通过key进行相关的类别设置
            setAuthorLBLM(newsEn,key);
            // 添加到总news中
            news.add(newsEn);
        }
        return news;
    }

    private void setAuthorLBLM(NewsBo newsEn, String key) {
//        设置为栏目
        newsEn.setAuthorType(String.valueOf(NewsConstant.LM_CODE));

//        设置为发布状态
        newsEn.setApplyStatus(NewsConstant.FaBu);
        //设置栏目作者id和设置来源
        if(key.equals("Life")){
            newsEn.setAuthor("31");
            newsEn.setCategories("31");
        }else if (key.equals("Recreation")){
            newsEn.setAuthor("33");
            newsEn.setCategories("33");
        }else if (key.equals("Finance")){
            newsEn.setAuthor("32");
            newsEn.setCategories("32");
        }else if (key.equals("Science")){
            newsEn.setAuthor("28");
            newsEn.setCategories("28");
        }
    }


//    public static MultipartFile getFileFromUrl(String url, String fileName) throws IOException {
//        // Create a resource from the URL
//        URL urlObj = new URL(url);
//        HttpURLConnection connection = (HttpURLConnection) urlObj.openConnection();
//        connection.setRequestMethod("GET");
//        connection.setConnectTimeout(10000);
//        connection.setReadTimeout(60000);
//        connection.setDoOutput(true);
//        DiskFileItemFactory fileItemFactory = new DiskFileItemFactory();
//        DiskFileItem fileItem = (DiskFileItem) fileItemFactory.createItem("file",
//            MediaType.ALL_VALUE, true, fileName);
//        fileItem.getOutputStream().flush();
//        try (ReadableByteChannel readableByteChannel = Channels.newChannel(connection.getInputStream());
//             OutputStream outputStream = fileItem.getOutputStream();
//             WritableByteChannel writableByteChannel = Channels.newChannel(outputStream)) {
//            // Create a byte buffer to store the file content
//            ByteBuffer buffer = ByteBuffer.allocateDirect(1024 << 2);
//
//            // Read the file content into the byte buffer
//            while (readableByteChannel.read(buffer) != -1) {
//                // Prepare the byte buffer to be read again
//                buffer.flip();
//                while (buffer.hasRemaining()) {
//                    writableByteChannel.write(buffer);
//                }
//                buffer.clear();
//            }
//        } catch (Exception e) {
//
//        }
//        return new CommonsMultipartFile(fileItem);
//    }


}

